package com.fdd.op.sdk;

import com.fdd.op.sdk.constants.Constants;
import com.fdd.op.sdk.domain.OAuth2AccessToken;
import com.fdd.op.sdk.internal.parser.json.ObjectJsonParser;
import com.fdd.op.sdk.internal.token.FddTokenStore;
import com.fdd.op.sdk.internal.token.stroe.CacheTokenStoreImpl;
import com.fdd.op.sdk.internal.util.FddHashMap;
import com.fdd.op.sdk.internal.util.FddUrlUtils;
import com.fdd.op.sdk.internal.util.WebUtils;
import com.fdd.op.sdk.response.AccessTokenResponse;
import org.apache.commons.codec.digest.DigestUtils;

import java.io.IOException;
import java.util.Date;
import java.util.LinkedHashMap;

/**
 * @author opadmin
 */
public class AccessTokenClient extends BaseClient {
    protected static final String ACCESSTOKEN_PATH = "/base/login/oauth2/accessToken";
    private static final FddTokenStore DEFAULT_STORE = new CacheTokenStoreImpl();
    /**
     * 缓存token，默认内存，建议生产实现FddTokenStore，使用redis缓存中间件来完成
     */
    private FddTokenStore tokenStore;
    /**
     * 请求地址
     */
    protected String serverUrl;
    /**
     * 默认连接超时时间为15秒
     */
    protected int connectTimeout = 15000;
    /**
     * 默认响应超时时间为30秒
     */
    protected int readTimeout = 30000;

    public AccessTokenClient(String serverUrl, String appId, String appKey) {
        super(appId, appKey);
        this.serverUrl = serverUrl;
    }

    public AccessTokenClient(String serverUrl, String appId, String appKey, int connectTimeout, int readTimeout) {
        this(serverUrl, appId, appKey);
        this.connectTimeout = connectTimeout;
        this.readTimeout = readTimeout;
    }

    public AccessTokenClient tokenStore(FddTokenStore tokenStore) {
        this.tokenStore = tokenStore;
        return this;
    }

    private LinkedHashMap getGenerateKeyParam() {
        LinkedHashMap map = new LinkedHashMap();
        map.put("serverUrl", this.serverUrl);
        map.put("appId", this.getAppId());
        map.put("apiKey", this.getApiKey());
        return map;
    }

    /**
     * 获取令牌
     */
    public String getAccessToken() throws ApiException {
        notNull(this.serverUrl, String.format("获取令牌失败:%s不能为空", "serverUrl"));
        notNull(this.getAppId(), String.format("获取令牌失败:%s不能为空", Constants.APP_ID));
        notNull(this.getApiKey(), String.format("获取令牌失败失败:%s不能为空", Constants.APP_KEY));
        if (tokenStore == null) {
            tokenStore = DEFAULT_STORE;
        }
        OAuth2AccessToken token = tokenStore.getAccessToken(getGenerateKeyParam());
        if (token != null) {
            return token.getAccessToken();
        }
        FddHashMap oauthParams = new FddHashMap();
        oauthParams.put(Constants.APP_ID, this.getAppId());
        oauthParams.put(Constants.TIMESTAMP, getCurrentTimestamp());
        //添加签名参数
        String sign = DigestUtils.sha256Hex(oauthParams.get(Constants.TIMESTAMP) + this.getApiKey()).toUpperCase();
        oauthParams.put(Constants.SIGN, sign);
        String realServerUrl = FddUrlUtils.getServerUrl(this.serverUrl, ACCESSTOKEN_PATH, null, null);
        String fullUrl = WebUtils.buildRequestUrl(realServerUrl);
        //获取令牌
        String res;
        try {
            res = WebUtils.doPostWithJson(fullUrl, oauthParams, Constants.CHARSET_UTF8, connectTimeout, readTimeout, null);
        } catch (IOException | AccessTokenException e) {
            throw new ApiException(e);
        }
        FddParser<AccessTokenResponse> parser = new ObjectJsonParser<>(AccessTokenResponse.class, true);
        AccessTokenResponse response = parser.parse(res);
        if (!response.isSuccess()) {
            return "";
        }
        String accessToken = response.getAccessToken().getAccessToken();
        tokenStore.storeAccessToken(response.getAccessToken(), getGenerateKeyParam());
        return accessToken;
    }


    private void notNull(Object object, String message) {
        if (object == null) {
            throw new IllegalArgumentException(message);
        }
    }

    private long getCurrentTimestamp() {
        return Long.parseLong(Constants.DATEFORMAT.format(new Date()));
    }
}
